using System.Collections;
using System.Collections.Generic;

namespace Fadd.Parser
{
    /// <summary>
    /// Base class for all objects that are used to build a tree.
    /// </summary>
    public abstract class Token : IEnumerable<Token>
    {
        private readonly List<Token> _items = new List<Token>();
        private Token _parent;

        /// <summary>
        /// Used to determine the kind of this token
        /// </summary>
        public abstract int TokenIdentifier
        { get; }

        /// <summary>
        /// Gets or sets the parent.
        /// </summary>
        /// <value>The parent.</value>
        public Token Parent
        {
            get { return _parent; }
            internal set { _parent = value; }
        }

        /// <summary>
        /// Last added child in the current node.
        /// </summary>
        public Token LastChild
        {
            get { return _items[_items.Count - 1]; }
        }
        /// <summary>
        /// Gets the items.
        /// </summary>
        /// <value>The items.</value>
        public IEnumerable<Token> Children
        {
            get { return _items; }
        }

        /// <summary>
        /// Get one of the children
        /// </summary>
        /// <param name="index">zero-based index.</param>
        /// <returns><see cref="Token"/></returns>
        public Token this[int index]
        {
            get { return _items[index]; }
        }


        /// <summary>
        /// Depth in parse tree.
        /// </summary>
        public int Depth
        {
            get
            {
                int depth = 0;
                Token parent = Parent;
                while (parent != null)
                {
                    ++depth;
                    parent = parent.Parent;
                }

                return depth;
            }
        }

        /// <summary>
        /// Number of children.
        /// </summary>
        public int Count
        {
            get { return _items.Count; }
        }
        /// <summary>
        /// Adds the specified child.
        /// </summary>
        /// <param name="child">The child.</param>
        public virtual void Add(Token child)
        {
            child.Parent = this;
            _items.Add(child);
        }

        /// <summary>
        ///                     Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        ///                     A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
        /// </returns>
        /// <filterpriority>1</filterpriority>
        public IEnumerator<Token> GetEnumerator()
        {
            return _items.GetEnumerator();
        }

        /// <summary>
        ///                     Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        ///                     An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _items.GetEnumerator();
        }

        /// <summary>
        /// String representation of the token
        /// </summary>
        /// <param name="includeChildren">Also include all children in the output</param>
        /// <returns>Returns a human friendly string</returns>
        public string ToString(bool includeChildren)
        {
            string temp = ToString();
            foreach (Token child in Children)
                temp += child.ToString(true);
            return temp;
        }
    }
}
